package cn.bearspark.article.provider.service.impl;

import cn.bearspark.article.dto.article.Article4ModifyDTO;
import cn.bearspark.article.dto.article.ArticleSimpleDTO;
import cn.bearspark.article.dto.article.ModifyArticleDTO;
import cn.bearspark.article.dto.article.PublishArticleDTO;
import cn.bearspark.article.provider.dao.buffer.ArticleBaseHashBuffer;
import cn.bearspark.article.provider.dao.buffer.ArticleCategoryIdListBuffer;
import cn.bearspark.article.provider.dao.buffer.ArticleIdListBuffer;
import cn.bearspark.article.provider.dao.co.ArticleCO;
import cn.bearspark.article.provider.dao.mapper.ArticleBaseMapper;
import cn.bearspark.article.provider.dao.mapper.ArticleCategoryMapper;
import cn.bearspark.article.provider.dao.mapper.ArticleImgMapper;
import cn.bearspark.article.provider.dao.po.article.ArticleBasePO;
import cn.bearspark.article.provider.dao.po.article.ArticleRepPO;
import cn.bearspark.article.provider.dao.repository.ArticleRepository;
import cn.bearspark.article.provider.service.ArticleService;
import cn.bearspark.article.provider.service.bo.*;
import cn.bearspark.common.aop.autoparse.host.AutoParseHost;
import cn.bearspark.common.enumeration.ModuleEnum;
import cn.bearspark.common.enumeration.VisibilityEnum;
import cn.bearspark.common.util.ConvertBeanUtil;
import cn.bearspark.common.util.ConvertInfoUtil;
import cn.bearspark.file.rpc.FileRpc;
import cn.bearspark.schedule.rpc.ScheduleRpc;
import com.alibaba.fastjson2.JSON;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.time.LocalDateTime;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author f
 */
@Service
public class ArticleServiceImpl implements ArticleService {

    /**
     * 默认的封面路径
     */
    private static final String DEFAULT_COVER_URL = "http://<h>/bear-spark/file/download/default-article-cover.png";

    @DubboReference
    private FileRpc fileRpc;
    @DubboReference
    private ScheduleRpc scheduleRpc;

    private final ArticleBaseMapper articleBaseMapper;
    private final ArticleImgMapper articleImgMapper;
    private final ArticleCategoryMapper articleCategoryMapper;

    private final ArticleRepository articleRepository;

    private final ArticleIdListBuffer articleIdListBuffer;
    private final ArticleBaseHashBuffer articleBaseHashBuffer;
    private final ArticleCategoryIdListBuffer articleCategoryIdListBuffer;

    public ArticleServiceImpl(ArticleBaseMapper articleBaseMapper,
                              ArticleImgMapper articleImgMapper,
                              ArticleCategoryMapper articleCategoryMapper,
                              ArticleRepository articleRepository,
                              ArticleIdListBuffer articleIdListBuffer,
                              ArticleBaseHashBuffer articleBaseHashBuffer,
                              ArticleCategoryIdListBuffer articleCategoryIdListBuffer) {
        this.articleBaseMapper = articleBaseMapper;
        this.articleImgMapper = articleImgMapper;
        this.articleCategoryMapper = articleCategoryMapper;
        this.articleRepository = articleRepository;
        this.articleIdListBuffer = articleIdListBuffer;
        this.articleBaseHashBuffer = articleBaseHashBuffer;
        this.articleCategoryIdListBuffer = articleCategoryIdListBuffer;
    }

    @Override
    @AutoParseHost(PublishArticleDTO.class)
    public void publish(PublishArticleDTO publishArticleDTO) {
        long articleId = publishArticleDTO.getArticleId();
        long userId = publishArticleDTO.getUserId();
        ArticleBasePO articleBasePO = ConvertBeanUtil.convert(publishArticleDTO, ArticleBasePO.class);
        List<String> imgUrlList = publishArticleDTO.getImgUrlList();

        // 如果封面为 null，则设置默认的封面
        if (articleBasePO.getCoverUrl() == null) {
            articleBasePO.setCoverUrl(DEFAULT_COVER_URL);
        } else {
            // 否则将封面添加到专栏的图片集合中
            imgUrlList.add(articleBasePO.getCoverUrl());
        }

        if (!CollectionUtils.isEmpty(imgUrlList)) {
            // 阻止删除上传的图片
            fileRpc.preventDeletion(imgUrlList);

            // 保存专栏的图片
            articleImgMapper.insertBatch(articleId, imgUrlList);
        }

        // 保存专栏 标题、摘要、内容 数据
        articleRepository.save(ConvertBeanUtil.convert(publishArticleDTO, ArticleRepPO.class));

        LocalDateTime pubTime = publishArticleDTO.getPubTime();
        articleBasePO.setUpdateTime(pubTime);
        if (LocalDateTime.now().isBefore(pubTime)) {
            // 设置定时发布的专栏
            articleBasePO.setPubTime(pubTime);
            Integer visibility = articleBasePO.getVisibility();
            articleBasePO.setVisibility(VisibilityEnum.INVISIBLE.getCode());

            // 提交定时发布的任务
            ScheduledArticleBO scheduledArticleBO = new ScheduledArticleBO();
            scheduledArticleBO.setArticleId(articleId);
            scheduledArticleBO.setVisibility(visibility);
            scheduleRpc.scheduled(ModuleEnum.ARTICLE.getCode(), pubTime, JSON.toJSONString(scheduledArticleBO));
        }

        // 保存专栏基础数据
        articleBaseMapper.insert(articleBasePO);

        // 保存专栏分类数据
        List<Long> categoryIdList = publishArticleDTO.getCategoryIdList();
        if (!categoryIdList.isEmpty()) {
            articleCategoryMapper.insertBatch(articleId, userId, publishArticleDTO.getVisibility(), categoryIdList);
        }

        // 清理用户的分类的专栏 id 缓存
        articleIdListBuffer.cleanBatch(userId);
    }

    @Override
    @AutoParseHost(Article4ModifyBO.class)
    public Article4ModifyBO get(long articleId, long userId) {
        // 如果专栏的发布者不是当前用户，则返回 null
        ArticleCO articleCO = articleBaseHashBuffer.get(articleId);
        if (articleCO.getUserId() != userId) {
            return null;
        }
        ArticleRepPO articleRepPO = articleRepository.getById(articleId);
        List<Long> categoryIdList = articleCategoryIdListBuffer.listCategoryId(articleId);

        Article4ModifyBO article4ModifyBO = ConvertBeanUtil.convert(articleCO, Article4ModifyBO.class);
        article4ModifyBO.setCategoryIdList(categoryIdList);
        article4ModifyBO.setTitle(articleRepPO.getTitle());
        article4ModifyBO.setSummary(articleRepPO.getSummary());
        article4ModifyBO.setContent(articleRepPO.getContent());
        return article4ModifyBO;
    }

    @Override
    public ArticleCategoryBO getCategoryInfo(long articleId, long userId) {
        // 如果专栏的发布者不是当前用户，则返回 null
        ArticleCO articleCO = articleBaseHashBuffer.get(articleId);
        if (articleCO.getUserId() != userId) {
            return null;
        }
        List<Long> categoryIdList = articleCategoryIdListBuffer.listCategoryId(articleId);

        ArticleCategoryBO articleCategoryBO = new ArticleCategoryBO();
        articleCategoryBO.setVisibility(articleCO.getVisibility());
        articleCategoryBO.setCategoryIdList(categoryIdList);
        return articleCategoryBO;
    }

    @Override
    @AutoParseHost(ModifyArticleDTO.class)
    public void modify(ModifyArticleDTO modifyArticleDTO, List<Long> oldCategoryIdList) {
        ArticleBasePO articleBasePO = ConvertBeanUtil.convert(modifyArticleDTO, ArticleBasePO.class);
        List<String> imgUrlList = modifyArticleDTO.getImgUrlList();

        // 如果封面为 null，则设置默认的封面
        if (articleBasePO.getCoverUrl() == null) {
            articleBasePO.setCoverUrl(DEFAULT_COVER_URL);
        } else {
            // 否则将封面添加到专栏的图片集合中
            imgUrlList.add(articleBasePO.getCoverUrl());
        }
        if (!CollectionUtils.isEmpty(imgUrlList)) {
            // 阻止删除上传的图片
            fileRpc.preventDeletion(imgUrlList);
        }

        // 修改专栏基础数据
        articleBaseMapper.update(articleBasePO);

        // 修改专栏 标题、摘要、内容 数据
        articleRepository.update(ConvertBeanUtil.convert(modifyArticleDTO, ArticleRepPO.class));

        // 如果旧分类 id 集合和新分类 id 集合不一样，则修改专栏分类数据
        long userId = modifyArticleDTO.getUserId();
        long articleId = modifyArticleDTO.getArticleId();
        List<Long> newCategoryIdList = modifyArticleDTO.getCategoryIdList();
        if (oldCategoryIdList.size() != newCategoryIdList.size() &&
            !new HashSet<>(oldCategoryIdList).containsAll(new HashSet<>(newCategoryIdList))) {
            articleCategoryMapper.deleteByArticleId(articleId);
            articleCategoryMapper.insertBatch(articleId, userId, modifyArticleDTO.getVisibility(), newCategoryIdList);
            articleCategoryIdListBuffer.clean(articleId);
        }

        // 清理专栏基础数据的缓存
        articleBaseHashBuffer.clean(articleId);
        // 清理用户的分类的专栏 id 缓存
        articleIdListBuffer.cleanBatch(userId);
    }

    @Override
    public ArticleDeleteBO delete(long articleId, long userId) {
        // 获取专栏数据，如果获取不到，说明没有权限，直接返回；如果专栏的可见性为 不可见，也直接返回
        ArticleCO articleCO = articleBaseHashBuffer.get(articleId);
        if (articleCO.getUserId() != userId || articleCO.getVisibility() == VisibilityEnum.INVISIBLE.getCode()) {
            return null;
        }
        List<Long> categoryIdList = articleCategoryIdListBuffer.listCategoryId(articleId);

        // 删除专栏的图片
        List<String> imgUrlList = articleImgMapper.listByArticleId(articleId);
        if (!imgUrlList.isEmpty()) {
            fileRpc.deleteBatch(imgUrlList);
            articleImgMapper.deleteByArticleId(articleId);
        }

        // 删除专栏的分类数据
        articleCategoryMapper.deleteByArticleId(articleId);

        // 删除专栏基础数据
        articleBaseMapper.deleteById(articleId);

        // 删除专栏 标题、摘要、内容 数据
        articleRepository.deleteById(articleId);

        // 清理专栏数据的缓存
        articleBaseHashBuffer.clean(articleId);
        articleCategoryIdListBuffer.clean(articleId);
        articleIdListBuffer.cleanBatch(userId);

        ArticleDeleteBO articleDeleteBO = new ArticleDeleteBO();
        articleDeleteBO.setCategoryIdList(categoryIdList);
        articleDeleteBO.setVisibility(articleCO.getVisibility());
        articleDeleteBO.setHappeningId(articleCO.getHappeningId());
        return articleDeleteBO;
    }

    @Override
    @AutoParseHost(ArticleDetailBO.class)
    public ArticleDetailBO detail(long articleId, long userId) {
        ArticleCO articleCO = articleBaseHashBuffer.get(articleId);

        // 如果专栏是 不可见 的，或者用户没有足够的权限，则返回 null
        long publisherId = articleCO.getUserId();
        int visibility = articleCO.getVisibility();
        if (visibility == VisibilityEnum.INVISIBLE.getCode()
            || visibility == VisibilityEnum.PRIVATE.getCode() && userId != publisherId) {
            return null;
        }
        ArticleRepPO articleRepPO = articleRepository.getTCById(articleId);
        List<Long> categoryIdList = articleCategoryIdListBuffer.listCategoryId(articleId);

        ArticleDetailBO articleDetailBO = ConvertInfoUtil.convert(articleCO, ArticleDetailBO.class);
        articleDetailBO.setPublisherId(publisherId);
        articleDetailBO.setTitle(articleRepPO.getTitle());
        articleDetailBO.setContent(articleRepPO.getContent());
        articleDetailBO.setCategoryIdList(categoryIdList);
        return articleDetailBO;
    }

    @Override
    @AutoParseHost(ArticleSimpleDTO.class)
    public List<ArticleSimpleDTO> page(int pageNum, int pageSize, Long categoryId, long userId, long listedUserId) {
        List<Long> articleIdList = articleIdListBuffer.page(pageNum, pageSize, categoryId, userId, listedUserId);
        Map<Long, ArticleCO> articleCOMap = articleBaseHashBuffer.mapSimple(articleIdList);
        Map<Long, ArticleRepPO> articleRepPOMap = articleRepository.mapTS(articleIdList);

        return articleIdList.stream().map(articleId -> {
            ArticleSimpleDTO articleSimpleDTO = ConvertInfoUtil.convert(
                    articleCOMap.get(articleId), ArticleSimpleDTO.class);
            ArticleRepPO articleRepPO = articleRepPOMap.get(articleId);
            articleSimpleDTO.setTitle(articleRepPO.getTitle());
            articleSimpleDTO.setSummary(articleRepPO.getSummary());
            return articleSimpleDTO;
        }).toList();
    }

    @Override
    public void incrCollectNum(long articleId) {
        articleBaseMapper.incrCollectNum(articleId);

        articleBaseHashBuffer.cleanHot(articleId);
    }

    @Override
    public void decrCollectNum(long articleId) {
        articleBaseMapper.decrCollectNum(articleId);

        articleBaseHashBuffer.cleanHot(articleId);
    }

    @Override
    public void incrMeritNum(long articleId) {
        articleBaseMapper.incrMeritNum(articleId);

        articleBaseHashBuffer.cleanHot(articleId);
    }

    @Override
    public void onArticleDeadline(List<String> infoList) {
        // 修改专栏的可见性
        infoList.stream()
                .map(info -> JSON.parseObject(info, ScheduledArticleBO.class))
                .collect(Collectors.groupingBy(
                        ScheduledArticleBO::getVisibility,
                        Collectors.mapping(
                                Function.identity(),
                                Collectors.mapping(ScheduledArticleBO::getArticleId, Collectors.toList())
                        )
                )).forEach(articleBaseMapper::updateVisibility);
    }
}
